<?php

/**
 * Класс для работы с базой данных MySQL черезинтерфейс PDO
 * 
 * Реализует такие методы как вставка/удаление сообщений, комментариев,
 * получение сообщения/комментария по их ID и всех записей из таблиц,
 * обновление сообщения/комментария
 *
 * @author nk11k
 */

class PDODB {

    /** #@+
     * @var String
     */
    
    private $HOSTNAME;
    private $USERNAME;
    private $PASSWORD;
    private $DBNAME;

    /**
     * Имя таблицы сообщений в базе данных
     */
    private $TBLMESSAGES;
    /**
     * Имя таблицы комментариев в базе данных
     */
    private $TBLCOMMENTS;

    /** #@- */


    /**
     * Константа для вызова отладочного кода
     */
    const DBG = TRUE;

    /**
     * Дескриптор соединения с базой данных (ресурс)
     *
     * @access private
     * $var resource
     */
    private $link;

    /**
     * Конструктор класса
     *
     * Устанавливает соединение с базой данных MySQL, выбирает базу и устанавливает кодировку UTF8
     */
    function __construct() {
        echo '<br> construct PDODB';
        global $cfg;        
        $this->HOSTNAME = $cfg->hostname;
        $this->USERNAME = $cfg->username;
        $this->PASSWORD = $cfg->password;
        $this->DBNAME = $cfg->dbname;
        $this->TBLMESSAGES = $cfg->msgtable;
        $this->TBLCOMMENTS = $cfg->cmttable;
        try {
            $this->link = new PDO(
                    "mysql:host=". $this->HOSTNAME . ";dbname=" . $this->DBNAME,
                    $this->USERNAME,
                    $this->PASSWORD,
                    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
            if (self::DBG) echo '<br>Connected to database';
            /* добавляем поддержку исключений */
            $this->link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->link->setAttribute(PDO::ATTR_EMULATE_PREPARES, TRUE); //bug: https://bugs.php.net/bug.php?id=44639&thanks=6
        } catch (PDOException $e) {
            echo $e->getMessage();
        }
    }

    function __destruct() {
        $this->link = NULL;
    }

    /**
     * Метод для получения всех сообщений из таблицы
     *
     * @access public
     * @return array двумерный массив строк, полученных в результате запроса, или FALSE, если запрос пуст/не удался
     */
    public function getAllMessages() {
        try {
            $statementhdl = $this->link->prepare("SELECT * FROM `" . $this->TBLMESSAGES .
                                               "` ORDER BY datetime DESC");
            $success = $statementhdl->execute();
            if (!$success) return FALSE;
            $rows = $statementhdl->fetchAll();
            return $rows;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;
        }
    }

    /**
     * Метод для получения сообщения из таблицы по его ID
     *
     * @access public
     * @param String $messageid номер сообщения ленты, которое следует запросить из базы
     * @return array строки, полученные в результате запроса, или FALSE, если запрос пуст/не удался
     */
    public function getMessageByID($messageid) {
        if (!is_numeric($messageid)) {
            if (self::DBG) {
                echo ('<br>getMessageByID: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
            }
            return FALSE;
        }
        try {
            
            $statementhdl = $this->link->prepare("SELECT * FROM `" . $this->TBLMESSAGES .
                                               "` WHERE messageid = :msgid");  
            $statementhdl->execute(array(':msgid' => $messageid));

            $row = $statementhdl->fetch();
            return $row;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }
    }

    /**
     * Метод для получения всех комментариев из таблицы
     *
     * @access public
     * @param Integer $messageid номер сообщения ленты, для которого следует получить комментарии
     * @return array двумерный массив строк, полученных в результате запроса, или FALSE, если запрос пуст/не удался
     */
    public function getAllCommentsToMessage($messageid) {
        if (!is_numeric($messageid)) {
            if (self::DBG) {
                echo ('<br>getAllCommentsToMessage: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
            }
            return FALSE;
        }
        try {
            
            $statementhdl = $this->link->prepare("SELECT * FROM `" . $this->TBLCOMMENTS . 
                                               "` WHERE messageid = :msgid");  
            $statementhdl->execute(array(
                ':msgid' => $messageid));

            $rows = $statementhdl->fetchAll();
            return $rows;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }
    }

    /**
     * Метод для получения комментария из таблицы по его ID
     *
     * @access public
     * @param Integer $messageid номер сообщения ленты, для которого следует получить комментарий
     * @param Integer $cmtid номер комментария
     * @return array строки, полученные в результате запроса, или FALSE, если запрос пуст/не удался
     */
    public function getCommentaryByID($messageid, $cmtid) {
        if (!is_numeric($messageid) || !is_numeric($cmtid)) {
            if (self::DBG) {
                echo ('<br>getCommentaryByID: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
                echo ('<br>$cmtid is ' . gettype($cmtid));
            }
            return FALSE;
        }
        try {
            
            $statementhdl = $this->link->prepare("SELECT * FROM `" . $this->TBLCOMMENTS .
                                               "` WHERE messageid = :msgid AND commentid = :cmtid");  
            $statementhdl->execute(array(
                ':msgid' => $messageid,
                ':cmtid' => $cmtid));

            $row = $statementhdl->fetch();
            return $row;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }
    }
    /**
     * Метод для добавления сообщения в ленту
     *
     * @access public
     * @param String $text текст сообщения
     * @param String $author имя автора сообщения
     * @return Boolean TRUE в случае успешного завершения метода, иначе - FALSE
     */
    public function addMessage($text, $author) {
        if (!is_string($text) || !is_string($author)) {
             if (self::DBG) {
                echo ('<br>addMessage: wrong argument type');
                echo ('<br>$text is ' . gettype($text));
                echo ('<br>$author is ' . gettype($author));
             }
            return FALSE;                        
        }
        try {            
            $statementhdl = $this->link->prepare(
                    "INSERT INTO `" . $this->TBLMESSAGES .
                    "` (text, author, datetime, modified)
                     VALUES (:txt, :author, NOW(), NOW())");  
            $success = $statementhdl->execute(array(
                ':txt' => $text,
                ':author' => $author));

            return $success;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }
    }

    /**
     * Метод для добавления комментария в ленту
     *
     * @access public
     * @param Integer $messageid номер сообщения ленты, для которого следует добавить комментарий
     * @param String $text текст сообщения
     * @param String $author имя автора сообщения
     * @return Boolean TRUE в случае успешного завершения метода, иначе - FALSE
     */
    public function addCommentary($messageid, $text, $author) {
        if (!is_numeric($messageid) || 
            !is_string($text)       || 
            !is_string($author)) {
             if (self::DBG) {
                echo ('<br>addCommentary: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
                echo ('<br>$text is ' . gettype($text));
                echo ('<br>$author is ' . gettype($author));
             }
            return FALSE;            
        }
        
        try {            
            $statementhdl = $this->link->prepare(
                    "INSERT INTO `" . $this->TBLCOMMENTS .
                    "` (messageid, text, author, datetime)
                     VALUES (:msgid, :txt, :author, NOW())");
            $statementhdl->bindValue(':msgid', (int) $messageid, PDO::PARAM_INT);
            $statementhdl->bindValue(':txt', $text);
            $statementhdl->bindValue(':author', $author);

            $success = $statementhdl->execute();
            /*
            $success = $statementhdl->execute(array(
                ':txt' => $text,
//                ':msgid' => $messageid,
                ':author' => $author));*/
            return $success;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            echo "<br>" . $e->getTraceAsString();
            return FALSE;                   
        }
    }

    /**
     * Метод для обновления сообщения в ленте
     *
     * @access public
     * @param Integer $messageid номер сообщения ленты, который следует изменить
     * @param String $text текст сообщения
     * @param String $author имя автора сообщения
     * @return Boolean TRUE в случае успешного завершения метода, иначе - FALSE
     */
    public function updateMessage($messageid, $text, $author) {
        if (!is_numeric($messageid) || 
            !is_string($text)       || 
            !is_string($author)) {
             if (self::DBG) {
                echo ('<br>updateMessage: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
                echo ('<br>$text is ' . gettype($text));
                echo ('<br>$author is ' . gettype($author));
             }
            return FALSE;
            }            
        try {            
            $statementhdl = $this->link->prepare(
                    "UPDATE `" . $this->TBLMESSAGES .
                  "` SET text = :txt, author = :author, modified = NOW()
                     WHERE messageid = :msgid");
            $success = $statementhdl->execute(array(                
                ':txt' => $text,
                ':msgid' => $messageid,
                ':author' => $author));
            return $success;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }
    }

    /**
     * Метод для обновления комментария в ленте
     *
     * @access public
     * @param Integer $messageid номер сообщения ленты, который содержит комментарий
     * @param Integer $cmtid номер комментария, который следует изменить
     * @param String $text текст сообщения
     * @param String $author имя автора сообщения
     * @return Boolean TRUE в случае успешного завершения метода, иначе - FALSE
     */
    public function updateCommentary($messageid, $cmtid, $text, $author) {
        if (!is_numeric($messageid) || 
            !is_numeric($cmtid)     || 
            !is_string($text)       || 
            !is_string($author)) {
             if (self::DBG) {
                echo ('<br>updateCommentary: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
                echo ('<br>$cmtid is ' . gettype($cmtid));
                echo ('<br>$text is ' . gettype($text));
                echo ('<br>$author is ' . gettype($author));
            }
            return FALSE;
           }        
        try {            
            $statementhdl = $this->link->prepare(
                    "UPDATE `" . $this->TBLCOMMENTS .
                    "` SET text = :txt, author = :author
                       WHERE messageid = :msgid AND commentid = :cmtid");
            $success = $statementhdl->execute(array(
                ':msgid' => $messageid,
                ':cmtid' => $cmtid,                
                ':txt' => $text,
                ':author' => $author));
            return $success;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }

    }

    /**
     * Метод для удаления сообщения из ленты
     * 
     * Выполняет SQL-запрос на удаления сообщения по его $messageid, при этом
     * комментарии корректно удаляются, поскольку таблица имеет параметр ON DELETE CASCADE
     * 
     * @access public
     * @param integer $messageid номер сообщения
     * @return boolean в случае ошибки возвращает false и наоборот
     */
    public function deleteMessage($messageid) {
        if (!is_numeric($messageid)) {
            if (self::DBG) {
                echo ('<br>deleteMessage: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
            }
            return FALSE;
        }
        try {
            $statementhdl = $this->link->prepare(
                    "DELETE FROM `" . $this->TBLMESSAGES .
                  "` WHERE messageid = :msgid");
            $success = $statementhdl->execute(array(':msgid' => $messageid));
            return $success;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }
    }
    
    /**
     * Метод для удаления комментария из ленты
     * 
     * Выполняет SQL-запрос на удаления комментария по его $messageid и $commentaryid
     * 
     * @access public
     * @param integer $messageid номер сообщения
     * @param integer $commentaryid номер комментария
     * @return boolean в случае ошибки возвращает false и наоборот
     */
    public function deleteCommentary($messageid, $commentaryid) {
        if (!is_numeric($messageid) || !is_numeric($commentaryid)) {
            if (self::DBG) {
                echo ('<br>deleteCommentary: wrong argument type');
                echo ('<br>$messageid is ' . gettype($messageid));
                echo ('<br>$commentaryid is ' . gettype($commentaryid));
            }
            return FALSE;
        }
        try {
            $statementhdl = $this->link->prepare(
                    "DELETE FROM `" . $this->TBLCOMMENTS .
                  "` WHERE messageid = :msgid AND commentid = :cmtid");
            $success = $statementhdl->execute(array(
                ':cmtid' => $commentaryid,
                ':msgid' => $messageid));
            return $success;
        } catch (PDOException $e) {
            echo "<br>Error:" . $e->getMessage();
            return FALSE;                   
        }
    }
}